﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DBMigrator.Core.DbObjects.Column;
using DBMigrator.Core.DbObjects.ForeignKey;
using Rhino.Mocks;
using StructureMap;
using Xunit;

namespace DBMigrator.Core.Tests.DbObjects.Column
{
    public class AddColumnTests
    {
        [Fact]
        public void SqlGenerationTypeShouldReturnIAddColumn()
        {
            Assert.Equal(typeof(IAddColumn), new AddColumn<string>("test").SqlGenerationType);
        }

        [Fact]
        public void TypeShouldReturnGenericType()
        {
            Assert.Equal(typeof(SerializableAttribute), new AddColumn<SerializableAttribute>("Name").Type);
        }

        [Fact]
        public void OneParameterConstructorShouldThrowIfNameIsNull()
        {
            Assert.Throws<ArgumentNullException>(() => new AddColumn<object>(null));
        }

        [Fact]
        public void OneParameterConstructorShouldThrowIfNameIsBlank()
        {
            Assert.Throws<ArgumentNullException>(() => new AddColumn<object>(string.Empty));
        }

        [Fact]
        public void TwoParameterConstructorShouldThrowIfNameIsNull()
        {
            Assert.Throws<ArgumentNullException>(() => new AddColumn<object>(null, 1));
        }

        [Fact]
        public void TwoParameterConstructorShouldThrowIfNameIsBlank()
        {
            Assert.Throws<ArgumentNullException>(() => new AddColumn<object>(string.Empty, 1));
        }

        [Fact]
        public void OneParameterConstructorShouldSetName()
        {
            var name = StringUtil.Random();
            Assert.Equal(name, new AddColumn<object>(name).Name);
        }

        [Fact]
        public void TwoParameterConstructorShouldSetName()
        {
            var name = StringUtil.Random();
            Assert.Equal(name, new AddColumn<object>(name, 1).Name);
        }

        [Fact]
        public void ThreeParameterConstructorShouldThrowIfLengthIsZero()
        {
            Assert.Throws<ArgumentException>(() => new AddColumn<object>("Test", 0));
        }

        [Fact]
        public void ThreeParameterConstructorShouldSetLength()
        {
            uint length = 5;
            Assert.Equal(length, new AddColumn<object>("Test", length).Length);
        }

        [Fact]
        public void SetAsPrimaryKeyShouldSetPrimaryKeyToTrue()
        {
            var addColumn = new AddColumn<object>("Name");
            Assert.False(addColumn.IsPrimaryKey);
            addColumn.SetAsPrimaryKey();
            Assert.True(addColumn.IsPrimaryKey);
        }

        [Fact]
        public void SetAsPrimaryKeyShouldReturnAddColumn()
        {
            var addColumn = new AddColumn<object>("Name");
            Assert.Equal(addColumn, addColumn.SetAsPrimaryKey());
        }

        [Fact]
        public void ReferencesShouldThrowIfPrimaryKeyTableIsNull()
        {
            Assert.Throws<ArgumentNullException>(() => new AddColumn<object>("Name")
                                                           .References(null, "PrimaryKeyColumn"));
        }

        [Fact]
        public void ReferencesShouldThrowIfPrimaryKeyTableIsEmpty()
        {
            Assert.Throws<ArgumentNullException>(() => new AddColumn<object>("Name")
                                                           .References(string.Empty, "PrimaryKeyColumn"));
        }

        [Fact]
        public void ReferencesShouldThrowIfPrimaryKeyColumnIsNull()
        {
            Assert.Throws<ArgumentNullException>(() => new AddColumn<object>("Name")
                                                           .References("PrimaryKeyTable", null));
        }

        [Fact]
        public void ReferencesShouldThrowIfPrimaryKeyColumnIsEmpty()
        {
            Assert.Throws<ArgumentNullException>(() => new AddColumn<object>("Name")
                                                           .References("PrimaryKeyTable", string.Empty));
        }

        [Fact]
        public void ReferencesShouldSetForeignKey()
        {
            var primaryKeyTable = StringUtil.Random();
            var primaryKeyColumn = StringUtil.Random();

            var addForeignKey = MockRepository.GenerateMock<IAddForeignKey>();
            ObjectFactory.Inject(addForeignKey);

            Assert.Equal(addForeignKey, new AddColumn<object>("Test").References(primaryKeyTable,
                primaryKeyColumn).ForeignKey);
        }

        [Fact]
        public void ReferencesShouldReturnAddColumn()
        {
            var addForeignKey = MockRepository.GenerateMock<IAddForeignKey>();
            ObjectFactory.Inject(addForeignKey);

            var addColumn = new AddColumn<object>("Test");

            Assert.Equal(addColumn, addColumn.References("Table", "Column"));
        }
    }
}
